<?php
// +--------------------+------------------+------+-----+---------+----------------+
// | Field              | Type             | Null | Key | Default | Extra          |
// +--------------------+------------------+------+-----+---------+----------------+
// | id                 | int(11)          | NO   | PRI | NULL    | auto_increment |
// | title              | varchar(255)     | NO   |     |         |                |
// | slug               | varchar(255)     | YES  |     |         |                |
// | first_category_id  | int(11) unsigned | YES  | MUL | 0       |                |
// | second_category_id | int(11) unsigned | YES  |     | 0       |                |
// | pc_cover_id        | int(11) unsigned | YES  |     | 0       |                |
// | wap_cover_id       | int(11) unsigned | YES  |     | 0       |                |
// | description        | varchar(255)     | NO   |     |         |                |
// | content            | text             | YES  |     | NULL    |                |
// | seo_description    | varchar(255)     | YES  |     |         |                |
// | seo_keywords       | varchar(255)     | YES  |     |         |                |
// | view_count         | int(11) unsigned | YES  |     | 0       |                |
// | status             | tinyint(1)       | YES  |     | 1       |                |
// | sort               | int(11)          | YES  |     | 0       |                |
// | is_recommand       | tinyint(1)       | YES  |     | 0       |                |
// | member_id          | int(11) unsigned | YES  |     | 0       |                |
// | create_time        | int(11) unsigned | YES  |     | 0       |                |
// | update_time        | int(11) unsigned | YES  |     | 0       |                |
// | delete_time        | int(11) unsigned | YES  |     | 0       |                |
// | host               | varchar(255)     | YES  |     |         |                |
// | address            | varchar(255)     | YES  |     |         |                |
// | unit_price         | varchar(50)      | YES  |     |         |                |
// | attachment_path    | varchar(255)     | YES  |     |         |                |
// | start_time         | int(11) unsigned | YES  |     | 0       |                |
// | end_time           | int(11) unsigned | YES  |     | 0       |                |
// +--------------------+------------------+------+-----+---------+----------------+
namespace app\common\model;

use think\facade\Config;
use think\facade\Cache;
use app\common\model\Base;
use app\common\validate\News as NewsValidate;
use app\common\validate\Column as ColumnValidate;
use app\common\validate\Notice as NoticeValidate;
use app\common\validate\Research as ResearchValidate;
use app\common\validate\Service as ServiceValidate;

class Article extends Base
{
    /**
     * BelongsTo 栏目
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-19
     * @return   [type]             [description]
     */
    public function firstCategory()
    {
        return $this->belongsTo('Category', 'first_category_id');
    }

    /**
     *  BelongsTo 栏目分类
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-19
     * @return   [type]             [description]
     */
    public function secondCategory()
    {
        return $this->belongsTo('Category', 'second_category_id')->bind([
                'second_category_title'  => 'title',
                'second_category_subed'  => 'is_subscribe',
                'second_category_applied'  => 'is_applied',
            ]);
    }

    /**
     * 与AuthGroup BelongsTo关联设置
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-07
     * @return   array              [description]
     */
    public function pcCover()
    {
        return $this->belongsTo('Upload', 'pc_cover_id')->bind([
                'pc_cover_path'  => 'save_path',
            ]);
    }

    /**
     * 与AuthGroup BelongsTo关联设置
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-07
     * @return   array              [description]
     */
    public function wapCover()
    {
        return $this->belongsTo('Upload', 'wap_cover_id')->bind([
                'wap_cover_path'  => 'save_path',
            ]);
    }

    /**
     * 与AuthGroup BelongsTo关联设置
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-07
     * @return   array              [description]
     */
    public function member()
    {
        return $this->belongsTo('Member')->bind([
                'member_name'  => 'name',
            ]);
    }

    /**
     * 列表搜索方法
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-07
     * @param    array              $param     搜索参数
     * @param    integer            $page_rows 每页显示数量
     * @return   Paginate
     */
    public function minePaginate($param, $page_rows = 0)
    {
        if($page_rows < 1){
            $page_rows = Config::get('paginate.list_rows');
        }

        $map = $this->parseSearchParam($param);

        $config = [];
        $config["query"] = $param;
        // 分页参数名是 page ，paginate方法内有获取到该值的方法
        $page = 1;
        if(isset($param["page"])){
            $page = intval($param["page"]);
        }
        $config["page"] = $page;

        $order_type = '';
        if(isset($param['order'])){
            $order_type = $param['order'];
        }
        $order_str = $this->queryOrderStr($order_type);
        $paginate = $this->with('pc_cover,second_category,member')->where($map)->order($order_str)->paginate($page_rows, false, $config);
        return $paginate;
    }

    /**
     * 用户前台列表搜索方法
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-20
     * @param    array              $param     用户请求参数
     * @param    integer            $page_rows [description]
     * @return   array                         [description]
     */
    public function userPaginate($param, $page_rows = 0)
    {
        if($page_rows < 1){
            $page_rows = Config::get('paginate.list_rows');
        }

        $default_param = [
            'only_active' => 1,
        ];
        $query_param = array_merge($param, $default_param);
        $map = $this->parseSearchParam($query_param);

        $config = [];
        // 过滤Paginate的分页参数
        $paginate_param = [];
        $allow_names = ['order'];
        foreach ($param as $key => $name) {
            if(isset($param[$name]) && $param[$name] != ''){
                $paginate_param[$name] = $param[$name];
            }
        }
        $config["query"] = $paginate_param;

        // 分页参数名是 page ，paginate方法内有获取到该值的方法
        $page = 1;
        if(isset($param["page"])){
            $page = intval($param["page"]);
        }
        $config["page"] = $page;

        $order_type = '';
        if(isset($param['order'])){
            $order_type = $param['order'];
        }
        $order_str = $this->queryOrderStr($order_type);
        $select_fields = [
            'id', 'title', 'second_category_id', 'pc_cover_id', 'description', 'view_count',
            "FROM_UNIXTIME(create_time, '%Y-%m-%d') AS create_date",
            "FROM_UNIXTIME(create_time, ' %H:%i:%S') AS create_hour",
        ];
        $paginate = $this->with('pc_cover')->field($select_fields)->where($map)->order($order_str)->paginate($page_rows, false, $config);
        return $paginate;
    }

    /**
     * 热门列表
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-22
     * @param    integer            $first_category_id 一级分类（栏目）ID
     * @param    integer            $limit_count       返回记录数量
     * @return   array                                 [description]
     */
    public function hotList($first_category_id, $limit_count){
        // 缓存Key列表
        $cache_keys = $this->cacheKeys();
        // 当前方法的缓存key
        $current_cache_key = NULL;
        $cache_item = false;
        if(isset($cache_keys['hot_list'])){
            $current_cache_key = $cache_keys['hot_list'];
            $cache_item = Cache::get($current_cache_key);
        }
        if(!is_array($cache_item)){
            $cache_item = [];
        }

        $node_cache_key = "c{$first_category_id}_l{$limit_count}";
        if(isset($cache_item[$node_cache_key]) && !empty($cache_item[$node_cache_key])){
            $list = $cache_item[$node_cache_key];
            foreach ($list as $key => &$item) {
                $item = $this->cacheReadItem($item);
            }
            return $list;
        }

        $map[] = ['status', '=', 1];
        $map[] = ['first_category_id', '=', intval($first_category_id)];

        $select_fields = [
            'id', 'title', 'second_category_id', 'pc_cover_id', 'description', 'view_count',
            "FROM_UNIXTIME(create_time, '%Y-%m-%d') AS create_date",
            "FROM_UNIXTIME(create_time, ' %H:%i:%S') AS create_hour",
        ];

        $order_str = $this->queryOrderStr('recommand');
        $list = $this->with('pc_cover')->field($select_fields)->where($map)->order($order_str)->limit($limit_count)->select();

        // 缓存数据
        if(!empty($list) && !empty($current_cache_key)){
            $cache_item[$node_cache_key] = $list;
            Cache::set($current_cache_key, $cache_item);

            foreach ($list as $key => $item) {
                $this->cacheSetItem($item);
            }
        }
        return $list;
    }

    /**
     * 热门记录
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-22
     * @param    integer            $second_category_id 所属二级分类
     * @param    integer            $first_category_id  [description]
     * @return   array                                  [description]
     */
    public function hotItem($second_category_id, $first_category_id = 0){
        // 缓存Key列表
        $cache_keys = $this->cacheKeys();
        // 当前方法的缓存key
        $current_cache_key = NULL;
        $cache_item = false;
        if(isset($cache_keys['hot_item'])){
            $current_cache_key = $cache_keys['hot_item'];
            $cache_item = Cache::get($current_cache_key);
        }
        if(!is_array($cache_item)){
            $cache_item = [];
        }

        // 当前二级节点的缓存key
        $second_category_id = intval($second_category_id);
        $node_cache_key = "c{$second_category_id}";
        if(isset($cache_item[$node_cache_key]) && !empty($cache_item[$node_cache_key])){
            $item = $cache_item[$node_cache_key];
            return $this->cacheReadItem($item);
        }

        $map[] = ['status', '=', 1];
        $map[] = ['second_category_id', '=', $second_category_id];
        if($first_category_id){
            $map[] = ['first_category_id', '=', intval($first_category_id)];
        }

        $select_fields = [
            'id', 'title', 'second_category_id', 'pc_cover_id', 'description', 'view_count',
            "FROM_UNIXTIME(create_time, '%Y-%m-%d') AS create_date",
            "FROM_UNIXTIME(create_time, ' %H:%i:%S') AS create_hour",
        ];

        $order_str = $this->queryOrderStr('recommand');
        $item = $this->with('pc_cover')->field($select_fields)->where($map)->order($order_str)->find();

        // 缓存数据
        if(!empty($item) && !empty($current_cache_key)){
            $cache_item[$node_cache_key] = $item;
            Cache::set($current_cache_key, $cache_item);

            $this->cacheSetItem($item);
        }

        return $item;
    }

    /**
     * 用户查看单条记录
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-19
     * @param    integer            $id              主键ID
     * @param    string             $view_mode       查看模式
     * @param    array              $validate_fields 验证字段列表
     * @return   array                               [description]
     */
    public function userFind($id, $view_mode, $validate_fields = []){
        $select_fields = [
            'id', 'title', 'first_category_id', 'second_category_id', 'pc_cover_id', 'description',
            'view_count', 'content', 'seo_description', 'status',
            'seo_keywords', 'host', 'address', 'unit_price',
            'attachment_path', 'start_time', 'end_time', 'status',
            "FROM_UNIXTIME(create_time, '%Y-%m-%d') AS create_date",
            "FROM_UNIXTIME(create_time, '%H:%i:%S') AS create_hour",
            "FROM_UNIXTIME(start_time, '%Y/%m/%d') AS start_date",
            "FROM_UNIXTIME(end_time, '%Y/%m/%d') AS end_date",
        ];
        $item = $this->with('pc_cover,second_category')->field($select_fields)->where('id', intval($id))->find();
        if(empty($item)){
            return [];
        }

        foreach ($validate_fields as $key => $value) {
            if($item[$key] != $value){
                return [];
            }
        }

        // 非预览模式
        if($view_mode != 'preview'){
            if(!$item['status']){
                //非预览只有status=1的可以查看
                return [];
            }

            //浏览次数加一
            $current_view_count = intval($item['view_count']);
            $item->view_count = $current_view_count+1;
            $save_status = $item->save();
            if(!$save_status){
                //浏览次数加一，保存失败
                $item->view_count = $current_view_count;
            }
            // 更新缓存数据
            $this->cacheSetItem($item);
        }


        $item['sub_state'] = $this->getSubState($item);

        return $item;
    }

    /**
     * 添加或更新记录
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-07
     * @param    array              $data 表单提交数据
     * @param    integer            $id   主键ID
     * @return   array                    更新结果
     */
    public function createOrUpdate($data, $id = 0)
    {
        $res = ['status' => false, 'data' => [], 'msg' => "添加或更新文章失败"];
        if($id > 0){
            $data['id'] = $id;
        }

        if(isset($data['validate_type'])){
            $validate_type = $data['validate_type'];
        }else{
            $validate_type = '';
        }
        switch ($validate_type) {
            case 'column':
                $validate = new ColumnValidate();
                break;
            case 'notice':
                $validate = new NoticeValidate();
                break;
            case 'research':
                $validate = new ResearchValidate();
                break;
            case 'service':
                $validate = new ServiceValidate();
                break;
            default:
                $validate = new NewsValidate();
                break;
        }

        if(isset($data['validate_secne'])){
            $validate_secne = $data['validate_secne'];
        }else{
            $validate_secne = 'default';
        }
        if(!$validate->scene($validate_secne)->check($data)){
            $res['msg'] = $validate->getError();
            return $res;
        }
        // return ['validate_type' => $validate_type, 'validate_secne' => $validate_secne, 'data' => $data];

        if(isset($data['id']) && $data['id'] > 0){
            $item = $this->where('id', $data['id'])->find();
        }else{
            $item = [];
        }
        if(empty($item)){
            $is_update = false;
            $msg = '添加文章成功';
        }else{
            $is_update = true;
            $msg = '更新文章成功';
            $data['id'] = $item['id'];
        }
        $this->data($data)->isUpdate($is_update)->allowField(true)->save();

        // 清除缓存数据
        $this->clearAllCache();

        $res = [
            'status' => true,
            'msg' => $msg,
            'data' => ['id' => $this->id],
        ];
        return $res;
    }

    // /**
    //  * 删除元素
    //  * @Author   zhanghong(Laifuzi)
    //  * @DateTime 2018-06-12
    //  * @param    integer            $first_category_id 所属栏目ID
    //  * @param    integer            $id                主键ID
    //  * @return   array
    //  */
    // public function deleteTypeItem($first_category_id, $id)
    // {
    //     $can_res = $this->canDeleteItem($id);
    //     if(!$can_res['status']){
    //         return $can_res;
    //     }

    //     $id = intval($id);
    //     $first_category_id = intval($first_category_id);
    //     $item = $this->where('id', $id)->where('first_category_id', $first_category_id)->find();
    //     if(empty($item)){
    //         $res['msg'] = '未找到删除记录';
    //         return $res;
    //     }
    //     $item->delete();
    //     // 因为模型事件只在调用模型的方法生效，使用查询构造器操作是无效的
    //     // 所以我们需要添加一个afterDeleteItem方法
    //     $this->afterDeleteItem($item);
    //     $res = [
    //         'status' => true,
    //         'msg' => '删除成功',
    //         'data' => ['id' => $id],
    //     ];
    //     return $res;
    // }

    /**
     * 删除记录后的执行方法
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-12
     * @param    array              $item [description]
     * @return   boolean                  [description]
     */
    protected function afterDeleteItem($item){
        // 清除缓存数据
        $this->clearAllCache();
        return true;
    }

    /**
     * 清除缓存数据
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-22
     * @return   [type]             [description]
     */
    public function clearAllCache()
    {
        $keys = $this->cacheKeys();
        foreach ($keys as $key => $name) {
            Cache::rm($name);
        }
    }

    /**
     * 排序后的操作
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-11
     * @return   boolean                   [description]
     */
    protected function afterResort(){
        // 清除缓存数据
        $this->clearAllCache();
        return true;
    }

    /**
     * 转化查询条件
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-07
     * @param    array              $param [description]
     * @return   array                     [description]
     */
    private function parseSearchParam($param)
    {
        $map = [];
        foreach ($param as $key => $value) {
            if(!is_array($value)){
                $value = trim($value);
            }
            switch ($key) {
            case 'id':
                $map[] = [$key, '=', intval($value)];
                break;
            case 'except_id':
                $map[] = ['id', '<>', intval($value)];
                break;
            case "first_category_id":
            case "second_category_id":
                if($value != ''){
                    $value = intval($value);
                    $map[] = [$key, '=', $value];
                }
                break;
            case "cat_id":
                if($value != ''){
                    $value = intval($value);
                    $map[] = ['second_category_id', '=', $value];
                }
                break;
            case "only_active":
                $value = intval($value);
                if($value > 0){
                    $map[] = ['status', '=', 1];
                }
                break;
            case "egt_time":
                $val = strtotime($value);
                if($val>=946656000){
                    $map[] = ['create_time', '>=', $val];
                }
                break;
            case "elt_time":
                $val = strtotime($value.' 23:59:59');
                if($val>=946656000){
                    $map[] = ['create_time', '<=', $val];
                }
                break;
            case "keyword":
                if(empty($value)){
                    continue;
                }else{
                    $keyword = "%{$value}%";
                }
                $map[] = ["title", "like", $keyword];
                break;
            }
        }
        return $map;
    }

    /**
     * 搜索排序方式
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-07
     * @param    string             $param 排序方式
     * @return   string                    [description]
     */
    protected function queryOrderStr($order_type = '')
    {
        switch ($order_type) {
            // case 'recommand':
            //     $str = 'is_recommand DESC, sort ASC, id ASC';
            //     break;
            default:
                $str = 'is_recommand DESC, sort ASC, id DESC';
                break;
        }
        return $str;
    }

    /**
     * 是否可以申请报名
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-21
     * @param    [type]             $item [description]
     * @return   string                   [description]
     */
    private function getSubState($item){
        if(!isset($item['second_category_subed']) || !$item['second_category_subed']){
            // Item所属属于不可以报名分类
            return 'missed';
        }
        if(!isset($item['start_time']) || !isset($item['end_time'])){
            return 'missed';
        }

        $current_time = time();
        if($item['start_time'] < 1){
            $is_started = true;
        }else if($current_time >= $item['start_time']){
            $is_started = true;
        }else{
            $is_started = false;
        }

        if($item['end_time'] < 1){
            $not_end = true;
        }else if($current_time <= $item['end_time']){
            $not_end = true;
        }else{
            $not_end = false;
        }

        if($is_started && $not_end){
            return 'processed';
        }else if($is_started == false){
            return 'padding';
        }else{
            // not end is false
            return 'finished';
        }
    }

    /**
     * 测试预览缓存数据
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-07-02
     * @param    [type]             $name [description]
     * @return   [type]                   [description]
     */
    public function showCacheValue($name){
        $cache_keys = $this->cacheKeys();
        if(!isset($cache_keys[$name])){
            return ['name' => 'not present'];
        }
        $current_cache_key = $cache_keys[$name];

        $res = [
            'name' => $name,
            'cache_key' => $current_cache_key,
            'value' => Cache::get($current_cache_key),
        ];
        return $res;
    }

    /**
     * 单独缓存更新频繁的数据（如view_count）
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-07-02
     * @param    array              $item [description]
     * @return   [type]                   [description]
     */
    private function cacheSetItem($item){
        $cache_keys = $this->cacheKeys();
        if(!isset($cache_keys['view_list'])){
            return false;
        }
        $current_cache_key = $cache_keys['view_list'];
        $cache_item = Cache::get($current_cache_key);
        if(!is_array($cache_item)){
            $cache_item = [];
        }

        $cache_item_data = [];
        $cache_fields = ['view_count'];
        foreach ($cache_fields as $key => $name) {
            $cache_item_data[$name] = $item[$name];
        }
        $cache_item[$item['id']] = $cache_item_data;
        Cache::set($current_cache_key, $cache_item);
        return true;
    }

    /**
     * 读取记录并与更新频率的数据合并后的结果
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-07-02
     * @param    array              $item [description]
     * @return   array                    [description]
     */
    private function cacheReadItem($item){
        $cache_keys = $this->cacheKeys();
        if(!isset($cache_keys['view_list'])){
            return $item;
        }
        $current_cache_key = $cache_keys['view_list'];
        $cache_item = Cache::get($current_cache_key);
        if(!is_array($cache_item)){
            return $item;
        }

        if(!isset($cache_item[$item['id']])){
            return $item;
        }
        $cache_vals = $cache_item[$item['id']];
        if(is_array($cache_vals)){
            foreach ($cache_vals as $name => $value) {
                $item[$name] = $value;
            }
        }

        return $item;
    }


    /**
     * 缓存Key
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-22
     * @param    [type]             $cache_type [description]
     * @return   [type]                         [description]
     */
    private function cacheKeys(){
        return [
            'hot_item' => 'art_hot_item',
            'hot_list' => 'art_hot_list',
            'view_list' => 'art_list',
        ];
    }
}
